package test;

import java.util.Date;
import java.util.List;

import org.hibernate.HibernateException;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import trip.*;
import dao.*;

public class PersonDAOTest extends Assert{
	private Person_tripDAO ptD = Factory.getInstance().getPerson_tripDAO();
	private CompanyDAO cD = Factory.getInstance().getCompanyDAO();
	private PersonDAO pD = Factory.getInstance().getPersonDAO();
	private TripDAO tD = Factory.getInstance().getTripDAO();
	
	@DataProvider
	public Object[][] personData() {
		return new Object[][] {
				{"x", "x", "x", "x", "x", true},
				{"LengthGreaterThenMaxGREATERGREATERGREATER", "x", "x", "x", "x", false},
				{"x", "LengthGreaterThenMaxGREATERGREATERGREATER", "x", "x", "x", false},
				{"x", "x", "LengthGreaterThenMaxGREATERGREATERGREATER", "x", "x", false},
				{"x", "x", "x", "LengthGreaterThenMaxGREATERGREATERGREATER", "x", false},
				{"x", "x", "x", "x", "LengthGreaterThenMaxGREATERGREATERGREATER",false},
				
				{null, "x", "x", "x", "x", false}, 
				{"x", null, "x", "x", "x", false}, 
				{"x", "x", null, "x", "x", true}, 
				{"x", "x", "x", null, "x", true}, 
				{"x", "x", "x", "x", null, true}, 
				
				{null, null, "x", "x", "x", false}, 
				{null, "x", null, "x", "x", false}, 
				{null, "x", "x", null, "x", false}, 
				{null, "x", "x", "x", null, false}, 
				{"x", null, null, "x", "x", false}, 
				{"x", null, "x", null, "x", false}, 
				{"x", null, "x", "x", null, false}, 
				{"x", "x", null, null, "x", true}, 
				{"x", "x", null, "x", null, true}, 
				{"x", "x", "x", null, null, true}, 
				
				{null, null, null, "x", "x", false},
				{null, null, "x", null, "x", false},
				{null, null, "x", "x", null, false},
				{null, "x", null, null, "x", false},
				{null, "x", null, "x", null, false},
				{null, "x", "x", null, null, false},
				{"x", null, null, null, "x", false},
				{"x", null, null, "x", null, false},
				{"x", null, "x", null, null, false},
				{"x", "x", null, null, null, true},
				
				{"x", null, null, null, null, false},
				{null, "x", null, null, null, false},
				{null, null, "x", null, null, false},
				{null, null, null, "x", null, false},
				{null, null, null, null, "x", false},
				
				{null, null, null, null, null, false}
		};
	}
	
	@Test(dataProvider="personData")
	public void dataTest(String first_name, String last_name, String middle_name, 
						 String phone_number, String email, boolean expected) {
		try {
			Integer count = pD.getAll().size();
			assertNotNull(count);
			Person person = new Person(1, first_name, last_name, middle_name, phone_number, email, new Date());
			pD.create(person);
			Person tmpPers = pD.getById(person.getId());
			assertNotNull(tmpPers);
			assertEquals(tmpPers.getId(), person.getId());
			assertEquals(tmpPers.getFirst_name(), person.getFirst_name());
			assertEquals(tmpPers.getLast_name(), person.getLast_name());
			assertEquals(tmpPers.getMiddle_name(), person.getMiddle_name());
			assertEquals(tmpPers.getPhone_number(), person.getPhone_number());
			assertEquals(tmpPers.getEmail(), person.getEmail());
			if (middle_name == null)
				assertEquals(tmpPers.getMiddle_name(), "");
			if (phone_number == null)
				assertEquals(tmpPers.getPhone_number(), "");
			if (email == null)
				assertEquals(tmpPers.getEmail(), "");
			person.setFirst_name(person.getFirst_name() + "new");
			pD.update(person);
			tmpPers = pD.getById(person.getId());
			assertNotNull(tmpPers);
			assertEquals(tmpPers.getId(), person.getId());
			assertEquals(tmpPers.getFirst_name(), person.getFirst_name());
			assertEquals(tmpPers.getLast_name(), person.getLast_name());
			assertEquals(tmpPers.getMiddle_name(), person.getMiddle_name());
			assertEquals(tmpPers.getPhone_number(), person.getPhone_number());
			assertEquals(tmpPers.getEmail(), person.getEmail());
			pD.delete(tmpPers);
			tmpPers = pD.getById(person.getId());
			assertNull(tmpPers);
			assertEquals(pD.getAll().size(), count.intValue());
			assertTrue(expected);
		} catch (HibernateException ex) {
			assertFalse(expected);
		}
	}
	
	
	@DataProvider
	public Object[][] personInfo() {
		return new Object[][] {
				{null, null, null, null, null, false},
				{"", "", "", "", "", true},
				{"templ", null, null, null, null, true},
				{"templ", "examp", null, null, null, true},
				{"templ", "examp", "il", null, null, true},
				{"templ", "examp", "il", "939", null, true},
				{"templ", "examp", "il", "939", "cs", true},
				{"LengthGreaterThenMaxGREATERGREATERGREATER", "examp", "il", "939", "cs", false},
				{"templ", "LengthGreaterThenMaxGREATERGREATERGREATER", "il", "939", "cs", false},
				{"templ", "examp", "LengthGreaterThenMaxGREATERGREATERGREATER", "939", "cs", false},
				{"templ", "examp", "il", "LengthGreaterThenMaxGREATERGREATERGREATER", "cs", false},
				{"templ", "examp", "il", "939", "LengthGreaterThenMaxGREATERGREATERGREATER", false},
		};
	}
		
	@Test(dataProvider="personInfo")
	public void getByInfo(String fN, String lN, String mN, String pN, String email, boolean expected) {
		List<Person> persons = pD.getAll();
		assertNotNull(persons);
		Person person = new Person(1, "Template", "Example", "Filter", "4959395590", "pk@cs.msu.su", new Date());
		pD.create(person);
		List<Person> pByI = pD.getByInfo(fN, lN, mN, pN, email, -1, -1, null, null);
		assertNotNull(pByI);
		if (pByI.size() == 0) {
			assertFalse(expected);
			for(Person pers : persons) {
				if (fN != null)
					assertFalse(pers.getFirst_name().toLowerCase().indexOf(fN.toLowerCase()) >= 0);
				if (lN != null)
					assertFalse(pers.getLast_name().toLowerCase().indexOf(lN.toLowerCase()) >= 0);
				if (mN != null)
					assertFalse(pers.getMiddle_name().toLowerCase().indexOf(mN.toLowerCase()) >= 0);
				if (pN != null)
					assertFalse(pers.getPhone_number().toLowerCase().indexOf(pN.toLowerCase()) >= 0);
				if (email != null)
					assertFalse(pers.getEmail().toLowerCase().indexOf(email.toLowerCase()) >= 0);
			}
		}
		else {
			if (fN == null && lN == null && mN == null && pN == null && email == null)
				fail();
			for(Person pers : pByI) {
				if (fN != null)
					assertTrue(pers.getFirst_name().toLowerCase().indexOf(fN.toLowerCase()) >= 0);
				if (lN != null)
					assertTrue(pers.getLast_name().toLowerCase().indexOf(lN.toLowerCase()) >= 0);
				if (mN != null)
					assertTrue(pers.getMiddle_name().toLowerCase().indexOf(mN.toLowerCase()) >= 0);
				if (pN != null)
					assertTrue(pers.getPhone_number().toLowerCase().indexOf(pN.toLowerCase()) >= 0);
				if (email != null)
					assertTrue(pers.getEmail().toLowerCase().indexOf(email.toLowerCase()) >= 0);
			}
		}
		pD.delete(person);
	}
	
	@Test
	public void getByCompanyTest() {
		List<Person> persons = pD.getAll();
		assertNotNull(persons);
		List<Company> comps = cD.getAll();
		assertNotNull(comps);
		List<Person_trip> pts = ptD.getAll();
		assertNotNull(pts);
		for(Company comp : comps) {
			List<Person> pByC = pD.getByCompany(comp);
			assertNotNull(pByC);
			if (pByC.size() != 0) {
				for(Person person : pByC) {
					boolean found = false;
					for(Person_trip pt : pts) {
						if (pt.getTrip().getCompany().equals(comp) && pt.getPerson().equals(person)) {
							found = true;
							break;
						}
					}
					assertTrue(found);
				}
			}
			else {
				boolean found = false;
				for(Person_trip pt : pts) {
					if (pt.getTrip().getCompany().equals(comp)) {
						found = true;
						break;
					}
				}
				assertTrue(found);
			}
		}
	}
	
	@Test
	public void getByTripTest() {
		List<Person> persons = pD.getAll();
		assertNotNull(persons);
		List<Trip> trips = tD.getAll();
		assertNotNull(trips);
		List<Person_trip> pts = ptD.getAll();
		assertNotNull(pts);
		for(Trip trip : trips) {
			List<Person> pByT = pD.getByTrip(trip);
			assertNotNull(pByT);
			if (pByT.size() != 0) {
				for(Person person : pByT) {
					boolean found = false;
					for(Person_trip pt : pts) {
						if (pt.getPerson().equals(person) && pt.getTrip().equals(trip)) {
							found = true;
							break;
						}
					}
					assertTrue(found);
				}
			} 
			else {
				boolean found = false;
				for(Person_trip pt : pts) {
					if (pt.getTrip().equals(trip)) {
						found = true;
						break;
					}
				}
				assertFalse(found);
			}
		}
	}
}
